package main

import (
	"bufio"
	"fmt"
	"net"
	"os"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"time"
)

// 清屏函数
func clearScreen() {
	// 使用ANSI转义序列清屏
	fmt.Print("\033[H\033[J")
	fmt.Print("\033[H\033[J")
}
func getLocalIP() (string, error) {
	if runtime.GOOS == "windows" {
		hostname, err := os.Hostname()
		if err != nil {
			return "", fmt.Errorf("无法获取主机名: %v", err)
		}
		ips, err := net.LookupIP(hostname)
		if err != nil {
			return "", fmt.Errorf("无法通过主机名解析IP: %v", err)
		}
		for _, ip := range ips {
			if ipv4 := ip.To4(); ipv4 != nil && !ip.IsLoopback() {
				return ipv4.String(), nil
			}
		}
		return "", fmt.Errorf("未找到有效的IPv4地址")
	} else {
		// 通过UDP连接到外部地址来获取本地IP
		conn, err := net.Dial("udp", "8.8.8.8:80")
		if err != nil {
			return "", fmt.Errorf("无法建立UDP连接: %v", err)
		}
		defer conn.Close()
		localAddr := conn.LocalAddr().(*net.UDPAddr)
		return localAddr.IP.String(), nil
	}
}

// 扫描单个端口，返回ip和端口是否开放
func scanPort(ip string, port int, timeout time.Duration) bool {
	address := fmt.Sprintf("%s:%d", ip, port)
	conn, err := net.DialTimeout("tcp", address, timeout)
	if err != nil {
		return false
	}
	conn.Close()
	return true
}

// 解析CIDR并返回所有主机IP
func hosts(cidr string) ([]net.IP, error) {
	ip, ipnet, err := net.ParseCIDR(cidr)
	if err != nil {
		return nil, err
	}

	var ips []net.IP
	for ip := ip.Mask(ipnet.Mask); ipnet.Contains(ip); inc(ip) {
		// 排除网络地址和广播地址
		ipCopy := make(net.IP, len(ip))
		copy(ipCopy, ip)
		ips = append(ips, ipCopy)
	}

	// 移除网络地址和广播地址
	if len(ips) >= 2 {
		return ips[1 : len(ips)-1], nil
	}
	return ips, nil
}

// 增加IP地址
func inc(ip net.IP) {
	for j := len(ip) - 1; j >= 0; j-- {
		ip[j]++
		if ip[j] > 0 {
			break
		}
	}
}

// 扫描整个网络的指定端口，返回开放端口的IP列表
func scanNetwork(networkCIDR string, port int) ([]string, error) {
	network, err := hosts(networkCIDR)
	if err != nil {
		return nil, err
	}

	var openHosts []string
	var wg sync.WaitGroup
	var mu sync.Mutex

	semaphore := make(chan struct{}, 100) // 控制最大并发数为100

	for _, ip := range network {
		wg.Add(1)
		go func(ip net.IP) {
			defer wg.Done()
			semaphore <- struct{}{}
			defer func() { <-semaphore }()
			ipStr := ip.String()
			if scanPort(ipStr, port, 1*time.Second) {
				mu.Lock()
				openHosts = append(openHosts, ipStr)
				mu.Unlock()
				fmt.Printf("%s:%d 是开放的\n", ipStr, port)
			}
		}(ip)
	}

	wg.Wait()
	return openHosts, nil
}

func main() {
	reader := bufio.NewReader(os.Stdin)

	for {
		clearScreen()

		localIP, err := getLocalIP()
		if err != nil {
			fmt.Println("无法获取本地IP:", err)
			return
		}
		fmt.Println("您的本地IP是:", localIP)

		// 切割IP，保留前三段
		parts := strings.Split(localIP, ".")
		if len(parts) < 3 {
			fmt.Println("无效的本地IP格式")
			return
		}
		defaultCIDR := fmt.Sprintf("%s.%s.%s.0/24", parts[0], parts[1], parts[2])

		fmt.Printf("请输入要扫描的网络CIDR（默认 %s）: ", defaultCIDR)
		networkCIDR, _ := reader.ReadString('\n')
		networkCIDR = strings.TrimSpace(networkCIDR)
		if networkCIDR == "" {
			networkCIDR = defaultCIDR
		}

		fmt.Print("请输入要扫描的端口（默认 22）: ")
		portStr, _ := reader.ReadString('\n')
		portStr = strings.TrimSpace(portStr)
		port := 22
		if portStr != "" {
			p, err := strconv.Atoi(portStr)
			if err == nil {
				port = p
			} else {
				fmt.Println("无效的端口输入，使用默认端口 22")
			}
		}

		openHosts, err := scanNetwork(networkCIDR, port)
		if err != nil {
			fmt.Println("扫描时出错:", err)
			fmt.Println("请重试...")
			time.Sleep(2 * time.Second)
			continue
		}

		if len(openHosts) > 0 {
			fmt.Printf("在网络 %s 中发现以下主机开放了端口 %d:\n", networkCIDR, port)
			for _, ip := range openHosts {
				fmt.Println(ip)
			}
		} else {
			fmt.Printf("在指定的网络中未找到开放端口 %d 的主机。\n", port)
		}
		break
	}
}
